package lib;

import java.io.File;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import rmi.ClientRmiInterface;
import rmi.Groupe;
import rmi.Log;
import rmi.Message;
import client.Client;

public class Fbcast extends Protocole{

	private int[][] tabProc;
	private int nbrproc;
	private HashMap<Integer ,Client> listClient;
	
	/**
	 * Constructeur.
	 * 
	 * @param listClient
	 * 					la liste de client
	 */
	public Fbcast(HashMap<Integer ,Client> listClient)
	{
		this.nbrproc=0;
		this.listClient = listClient;
	}
	

	/**
	 * initialiser les numeros de sequence des messages 
	 * en provenance de tous les autres processus ont la valeur 1
	 * 
	 * @param compteur 
	 * 				   le nombre de clients
	 */
	public void init(int compteur){
		if(this.nbrproc==0){
			this.nbrproc=compteur;
			tabProc = new int[nbrproc][nbrproc];
			for(int i=0;i<nbrproc;i++){
				for(int j=0;j<nbrproc;j++)
					tabProc[i][j]=1;
			}
		}
	}
	public void envMsg(Message msg) {
		Client c = listClient.get(msg.getId());

		int estampille = c.getEstampille().getEstampille();
		estampille++;
		c.getEstampille().setEstampille(estampille);
		msg.setDate(c.getEstampille());
		
	}

	
	public Message recuMsgs(Message msg, int id) {
		
		return null;
	}

	
	public void lancerThread(Message msg, File logfile, int flag, int length,
			ArrayList<Integer> list) {
		 if(flag==0)	
	      {
	    	  Log log=new Log(null,Log.Action.emmi,msg);
	    	  envMsg(msg);
	    	  
	    	  int k=0;
	    	  int[] listcl = Groupe.getListDelivrance(msg.getId(),listClient);
	    	  ThreadFbacst tbs[]=new ThreadFbacst[listcl.length];
	    	  for(Integer i:listcl)
				{
					/*
					* créer les threads pour sender message
					*/
	    		  tbs[k]=new ThreadFbacst(listClient.get(i), msg,tabProc);
					k++;
				}
				/*
				 * demarrer tous les thread
				 */
				for (int i = 0; i < tbs.length; i++) {
					tbs[i].start();
				}
				/*
				 * attendre tous les thread est fini
				 */
				for (ThreadFbacst s :tbs) {
					try {
						s.join();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
	    	  }
		
	}
	
	static class ThreadFbacst extends Thread
	{
		private Client c;
		private Message m;
		private int[][] tabProc;
		private ThreadFbacst(Client c,Message m,int[][] tabProc)
		{
			this.c=c;
			this.m=m;
			this.tabProc=tabProc;
		}
		
		public void run(){
			try {
					sleep((int)(Math.floor(Math.random()*Protocole.SLEEPTIMES)));
					int idcl=c.getTb().getId()-1;
					int idmsg=m.getId()-1;
					c.getList().add(m);
					/*
					 * si le sequence du message est superieur
					 * le numero de message doit reçu 
					 * on attend jusqu'a la message reçu
					 */
					if(m.getNsequence()>tabProc[idcl][idmsg])
					{	synchronized(c) {
							System.out.println("attente");
							c.wait();
							ClientRmiInterface serv=Groupe.initContext(c.getTb().getId());
							Iterator i=c.getList().iterator();
							boolean test=true;
							while(i.hasNext()&&test)
							{
								Message msg=(Message)i.next();
								if(tabProc[idcl][idmsg]==msg.getNsequence())
								{
									test=false;
									
									serv=Groupe.initContext(c.getTb().getId());
								    
								    	try {
											serv.update(msg);
											c.getList().remove(msg);
											tabProc[idcl][idmsg]++;
										} catch (RemoteException e) {
											e.printStackTrace();
										}
								    	
								    
									
								}
								
							}
								
						}
					}
					
					/*
					 * test si le numero de sequence du message
					 * égale le prochain numéro de séquence du message
					 */
					else if(tabProc[idcl][idmsg]==m.getNsequence())
					{
						synchronized(c) {
							
							ClientRmiInterface serv=Groupe.initContext(c.getTb().getId());
						    
						    	try {
									serv.update(m);
									c.getList().remove(m);
									tabProc[idcl][idmsg]++;
								} catch (RemoteException e) {
									e.printStackTrace();
								}
								c.notifyAll();
					}
					}
					
					
					
					
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
		}
	}
	
	public ArrayList<Message> recuMsg(Message msg, int aProc) {
		
		return null;
	}
		
		
	

}
